package com.gao.alg.thread;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.LockSupport;
import java.util.function.IntConsumer;
//输入：n = 5
//输出："0102030405"
// 这种方式有并发问题
public class ZeroEvenOdd2 {
    private int n;
    volatile int flag =1;
    static ConcurrentHashMap<Integer, Thread> map = new ConcurrentHashMap<>();
    public ZeroEvenOdd2(int n) {
        this.n = n;
    }
    public void zero(IntConsumer printNumber) throws InterruptedException {
        for (int i=1; i<=n; i++) {
            while (flag % 2 == 0) LockSupport.park();
            printNumber.accept(0);
            flag ++;
            if (flag % 4 == 0) LockSupport.unpark(map.get(2));
            if (flag % 4 == 2) LockSupport.unpark(map.get(1));
        }
    }
    public void even(IntConsumer printNumber) throws InterruptedException {
        for (int i=2; i<=n; i+=2) {
            while (flag % 4 != 0) LockSupport.park();
            printNumber.accept(i);
            flag ++;
            LockSupport.unpark(map.get(0));
        }
    }
    public void odd(IntConsumer printNumber) throws InterruptedException {
        for (int i=1; i<=n; i+=2) {
            while (flag % 4 != 2) LockSupport.park();
            printNumber.accept(i);
            flag ++;
            LockSupport.unpark(map.get(0));
        }
    }
    public static void main(String[] args) {
        ZeroEvenOdd2 zeroEvenOdd = new ZeroEvenOdd2(99);
        Thread threadOdd = new Thread(() -> {
            try {
                zeroEvenOdd.odd(System.out::print);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        map.putIfAbsent(1, threadOdd);
        Thread threadEven = new Thread(() -> {
            try {
                zeroEvenOdd.even(System.out::print);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        map.putIfAbsent(2, threadEven);
        Thread threadZero = new Thread(() -> {
            try {
                zeroEvenOdd.zero(System.out::print);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        map.putIfAbsent(0, threadZero);
        threadZero.start();
        threadOdd.start();
        threadEven.start();
    }
}
